﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;

namespace SksApp
{
    public class Yazarkasa
    {
        private Kasalar KasaCinsi { get; set; }
        private IYazarKasa _yazarkasa = null;
        public List<HareketSatiri> Lines { get; set; }
        public Musteri Musteri { get; set; }
        public List<OdemeHareketi> OdemeDetaylari { get; set; }
        public EvrakCinsleri EvrakTipi { get; set; }

        public Yazarkasa()
        {
            switch (Settings.Instance.GetValue(Information.KasaTipi))
            {
                case "TKS-20-N":
                    this.KasaCinsi = Kasalar.TKS_20N;
                    _yazarkasa = new TeknoPos();
                    _yazarkasa.PortNo = Settings.Instance.GetValue(Information.KasaPortNo);
                    break;
                case "Hugin_425TX":
                    this.KasaCinsi = Kasalar.Hugin_425TX;
                    _yazarkasa = new Hugin_425TX();
                    _yazarkasa.PortNo = Settings.Instance.GetValue(Information.KasaPortNo);
                    break;
                case "Sharp":
                    this.KasaCinsi = Kasalar.Sharp;
                    _yazarkasa = new Sharp();
                    _yazarkasa.PortNo = Settings.Instance.GetValue(Information.KasaPortNo);
                    break;
                case "İnter":
                    this.KasaCinsi = Kasalar.Sharp;
                    _yazarkasa = new InterMpos();
                    _yazarkasa.PortNo = Settings.Instance.GetValue(Information.KasaPortNo);
                    break;
            }
        }

        private bool HarfKontrol(string filtre)
        {
            return Convert.ToBoolean(filtre.ToCharArray().Where(x => !char.IsNumber(x) && x != ',').Count());
        }

        private string HarfTemizle(string filtre)
        {
            if (HarfKontrol(filtre))
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(filtre.ToCharArray().Where(x => Char.IsNumber(x) || x == ',').ToArray());
                return sb.ToString();
            }
            else
                return filtre;
        }

        public enum Kasalar : byte
        {
            TKS_20N = 0,
            Hugin_425TX = 1,
            Sharp = 2
        }

        public void StokGonder()
        {
            if (_yazarkasa != null)
                _yazarkasa.StokGonder();
        }

        public void DepartmanGonder()
        {
            if (_yazarkasa != null)
                _yazarkasa.DepartmanGonder();
        }

        public void FisGonder()
        {
            if (_yazarkasa == null)
                return;

            if (_yazarkasa is InterMpos)
            {
                ((InterMpos)_yazarkasa).EvrakTipi = this.EvrakTipi;
                ((InterMpos)_yazarkasa).Firma = this.Musteri;
                ((InterMpos)_yazarkasa).OdemeBilgileri = this.OdemeDetaylari;
                _yazarkasa.FisSatirGonder(Lines);
                return;
            }

            string detayli = Settings.Instance.GetValue(Information.DetayliSatisGonderilsin);
            bool detayliGonder = false;

            if (string.IsNullOrEmpty(detayli))
                detayliGonder = false;
            else
            {
                if (detayli == "Departman Satışı")
                    detayliGonder = false;
                else
                    detayliGonder = true;


                List<string> satirlar = new List<string>();
                if (detayliGonder) //ürün bilgisi gönderilecek
                {
                    foreach (var item in Lines)
                    {
                        if (BarkodCevirim.Terazilimi(item.Barkod.Barkodu))
                        {
                            string barkod = item.Barkod.Barkodu + (1000 * item.Miktar).ToString("00000");
                            satirlar.Add(barkod + BarkodCevirim.CalculateChecksumDigit(barkod));
                        }
                        else
                        {
                            for (int i = 0; i < item.Miktar; i++)
                            {
                                satirlar.Add(item.Barkod.Barkodu);
                            }
                        }
                    }
                }
                else
                {
                    using (SksEntity ent = new SksEntity())
                    {
                        var result = (from c in Lines
                                      group c by new { c.Urun.VergiID } into d
                                      select new
                                      {
                                          Tutar = d.Sum(x => x.Tutar),
                                          VergiID = d.Key.VergiID
                                      }).ToList();

                        var result2 = (from r in result join v in ent.VergiOranlari on r.VergiID equals v.ID select new { v.ID, v.Sira, r.Tutar }).ToList();

                        int idx = 0;
                        foreach (var item in result2)
                        {
                            satirlar.Add(string.Format("{0}{1}", string.Format("29{0}{1}", "9900" + item.Sira.ToString(), (item.Tutar / 10m * 1000).ToString("00000")), BarkodCevirim.CalculateChecksumDigit(string.Format("29{0}{1}", "9900" + item.Sira.ToString(), (item.Tutar / 10m * 1000).ToString("00000")))));
                            idx++;
                        }
                    }
                }

                if (satirlar.Count > 0)
                    _yazarkasa.FisSatirGonder(satirlar.ToArray());
            }
        }
    }

    public interface IYazarKasa
    {
        string PortNo { get; set; }
        void StokGonder();
        void DepartmanGonder();
        void FisSatirGonder(params string[] lines);
        void FisSatirGonder(List<HareketSatiri> lines);
    }

    public class TeknoPos : IYazarKasa
    {
        public string PortNo { get; set; }
        SerialPort _serial;

        public void StokGonder()
        {
            int stokMiktari = 0;
            using (SksEntity ent = new SksEntity())
            {
                var result = (from b in ent.Barkodlar
                              join s in ent.Stoklar on b.StokID equals s.ID
                              join v in ent.VergiOranlari on s.VergiID equals v.ID
                              select new { b.Barkodu, s.Adi, s.Fiyat1, v.Sira }).ToList();
                stokMiktari = result.Count + 11;

                using (StreamWriter sw = new StreamWriter("temp.plu", false))
                {
                    foreach (var item in ent.VergiOranlari.ToList())
                    {
                        sw.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}", "9900" + item.Sira.ToString(), item.Aciklama, (10m).ToString("n2"), item.Sira));
                    }

                    foreach (var item in result)
                    {
                        if (BarkodCevirim.Terazilimi(item.Barkodu))
                        {
                            sw.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}", item.Barkodu.Substring(2), item.Adi.RemoveTurkis(), item.Fiyat1.ToString("n2"), item.Sira));
                        }
                        else
                        {
                            sw.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}", item.Barkodu, item.Adi.RemoveTurkis(), item.Fiyat1.ToString("n2"), item.Sira));
                        }

                    }
                    sw.Close();
                }
            }
            if (File.Exists("teknopos.exe"))
            {
                ProcessStartInfo ps = new ProcessStartInfo("teknopos.exe", string.Format("\"{0}\" \"{1}\" {2} 10 0", this.PortNo, new FileInfo("temp.plu").FullName, stokMiktari));
                ps.WindowStyle = ProcessWindowStyle.Normal;
                Process.Start(ps);
            }
            else
                System.Windows.Forms.MessageBox.Show("Yazarkasa programı bulunamadı");

        }

        public void DepartmanGonder()
        {
            int stokMiktari = 0;
            using (SksEntity ent = new SksEntity())
            {
                var result = (from v in ent.VergiOranlari where v.Sira > 0 select new { v.Aciklama, v.Sira }).ToList();
                stokMiktari = result.Count;

                using (StreamWriter sw = new StreamWriter("temp.dep", false))
                {
                    foreach (var item in result)
                    {
                        sw.WriteLine(string.Format("{0}\t{1}\t{2}.00\t0.01", item.Aciklama, item.Sira, 650));
                    }
                    sw.Close();
                }
            }
            if (File.Exists("teknopos.exe"))
            {
                ProcessStartInfo ps = new ProcessStartInfo("teknopos.exe", string.Format("\"{0}\" \"{1}\" {2} 10 1", this.PortNo, new FileInfo("temp.dep").FullName, stokMiktari));
                ps.WindowStyle = ProcessWindowStyle.Normal;
                Process.Start(ps);
            }
            else
                System.Windows.Forms.MessageBox.Show("Yazarkasa programı bulunamadı");
        }

        public void FisSatirGonder(params string[] lines)
        {
            _serial = new SerialPort(this.PortNo);
            try
            {
                _serial.Open();

                if (_serial.IsOpen)
                {
                    foreach (string item in lines)
                    {
                        _serial.Write(item.Trim() + "\r");
                        Thread.Sleep(500);
                    }
                }
                else
                    System.Windows.Forms.MessageBox.Show("Bağlantı Açılamadı !");

                _serial.Close();
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        public void FisSatirGonder(List<HareketSatiri> lines)
        {
            throw new NotImplementedException();
        }
    }

    public class Fis
    {
        public int ID { get; set; }
        public string Adi { get; set; }
        public int KdvID { get; set; }
        public string Barkod { get; set; }
        public decimal Miktar { get; set; }
        public decimal Fiyat { get; set; }
        public decimal Tutar { get; set; }
    }

    public class InterMpos : IYazarKasa
    {
        private Musteri _musteri;
        public Musteri Firma
        {
            get
            {
                if (_musteri == null)
                    _musteri = new Musteri() { Kodu = "0", Adi = "Perakende", VergiDairesi = "", VergiNo = "0" };
                return _musteri;
            }
            set
            {
                _musteri = value;
            }
        }
        public EvrakCinsleri EvrakTipi { get; set; }
        public List<OdemeHareketi> OdemeBilgileri { get; set; }
        public string PortNo { get; set; }


        public void StokGonder()
        {
            System.Windows.Forms.MessageBox.Show("yazarkasa için dosya oluşturulamaz !");
        }
        public void DepartmanGonder()
        {
            System.Windows.Forms.MessageBox.Show("yazarkasa için dosya oluşturulamaz !");
        }
        public void FisSatirGonder(params string[] lines)
        {
            throw new NotImplementedException();
        }

        public void FisSatirGonder(List<HareketSatiri> lines)
        {
            string fileName = Path.Combine(PortNo, string.Format("{0}{1}{2}{3}{4}", DateTime.Now.Day.ToString("00"), DateTime.Now.Month.ToString("00"), DateTime.Now.Hour.ToString("00"), DateTime.Now.Minute.ToString("00"), DateTime.Now.Second.ToString("00")) + ".txt");
            using (StreamWriter sw = new StreamWriter(fileName, false, System.Text.Encoding.GetEncoding("ibm857")))
            {

                List<Fis> _fis = new List<Fis>();

                foreach (var item in lines)
                {
                    Fis fis = new Fis();
                    fis.Miktar = Math.Round(item.Miktar, 4);
                    fis.Fiyat = Math.Round((item.Tutar / item.Miktar), 2);
                    fis.Tutar = fis.Fiyat * fis.Miktar;
                    fis.ID = item.Urun.ID;
                    fis.KdvID = item.Urun.VergiID;
                    fis.Adi = item.UrunAdi;
                    fis.Barkod = item.Barkod.Barkodu;

                    _fis.Add(fis);
                }
                decimal olusanFisTutari = _fis.Select(x => x.Tutar).Sum();

                if (EvrakTipi == EvrakCinsleri.Fis)
                {
                    sw.WriteLine("INFO;{0};{1};", this.Firma.Adi.Assign(25), olusanFisTutari.ToString("0000000.00").Replace(',', '.'));
                }
                else if (EvrakTipi == EvrakCinsleri.Fatura)
                {
                    sw.WriteLine("INFO;{0};{1};", this.Firma.Adi.Assign(25), olusanFisTutari.ToString("0000000.00").Replace(',', '.'));
                    sw.WriteLine("CARI;{0};", Firma.Kodu.Mid(0, 20));
                    sw.WriteLine("ADRES;{0};", (Firma.Adi + " " + Firma.Adres).Mid(0, 80));
                    sw.WriteLine("VERGI;{0};{1};", Firma.VergiDairesi.Mid(0, 15), Firma.VergiNo.Mid(0, 15));
                    sw.WriteLine("FATURA;");
                }
                else
                {
                    sw.WriteLine("INFO;{0};{1};", this.Firma.Adi.Assign(25), olusanFisTutari.ToString("0000000.00").Replace(',', '.'));
                    sw.WriteLine("CARI;{0};", Firma.Kodu.Mid(0, 20));
                    sw.WriteLine("ADRES;{0};", (Firma.Adi + " " + Firma.Adres).Mid(0, 80));
                    sw.WriteLine("VERGI;{0};{1};", Firma.VergiDairesi.Mid(0, 15), Firma.VergiNo.Mid(0, 15));
                    sw.WriteLine("GPS;");
                }

                foreach (var item in _fis)
                {
                    int kdvSira = item.KdvID;
                    if (kdvSira > 0)
                        kdvSira -= 1;

                    sw.WriteLine("SATIS;{0};{1};{2};{3};{4};{5};", item.ID.ToString("000000"), item.Adi.Assign(20), item.Barkod.Assign(20), kdvSira.ToString("00"), item.Miktar.ToString("00.000").Replace(',', '.'), item.Fiyat.ToString("0000000.00").Replace(',', '.'));
                }

                using (SksEntity ent = new SksEntity())
                {
                    var odemetipleri = ent.OdemeTipleri.ToList();
                    var odemeler = (from o in OdemeBilgileri
                                    join t in odemetipleri on o.OdemeTipID equals t.ID
                                    group new { o, t } by new { t.Tip, t.ID } into g
                                    select new { Tip = g.Key.Tip, Tutar = g.Sum(x => x.o.OdemeTutari), No = g.Key.ID }).ToList();

                    foreach (var item in odemeler)
                    {
                        switch (item.Tip)
                        {
                            case 0:
                                sw.WriteLine("NAKIT;Kodu:{0};Müşteri:{1};{2};", Firma.Kodu.Mid(0, 35), Firma.Adi.Mid(0, 32), Math.Round((item.Tutar + 0.05m), 2).ToString("n2").Replace(',', '.'));
                                break;
                            default:
                                sw.WriteLine("KREDI;{0};;{1};{2};{3};", Cevir.Parse<int>(item.No).ToString("00"), Firma.Kodu.Mid(0, 35), Firma.Adi.Mid(0, 32), Math.Round((item.Tutar + 0.05m), 2).ToString("n2").Replace(',', '.'));
                                break;
                        }
                    }
                    sw.Close();
                }
            }
        }
    }

    public class Sharp : IYazarKasa
    {
        SerialPort _serial;
        public string PortNo { get; set; }

        public void StokGonder()
        {
            MsgBox.Show(MessageStyle.Uyari, "Uyarı", "Bu işlem Sharp yazarkasada desteklenmiyor !");
        }

        public void DepartmanGonder()
        {
            MsgBox.Show(MessageStyle.Uyari, "Uyarı", "Bu işlem Sharp yazarkasada desteklenmiyor !");
        }

        public void FisSatirGonder(params string[] lines)
        {
            _serial = new SerialPort(this.PortNo);
            try
            {
                _serial.BaudRate = 4800;
                _serial.DataBits = 7;
                _serial.Handshake = Handshake.RequestToSend;
                _serial.Parity = Parity.Odd;
                _serial.StopBits = StopBits.Two;
                _serial.Open();

                if (_serial.IsOpen)
                {
                    List<char> dizi = new List<char>();
                    foreach (string item in lines)
                    {
                        dizi.Add(Convert.ToChar(2));
                        if (item.Length >= 13)
                            dizi.AddRange(("F" + item + "\r\n").ToCharArray());
                        else
                            dizi.AddRange(("FF" + item + "\r\n").ToCharArray());

                        _serial.Write(dizi.ToArray(), 0, dizi.Count);
                        dizi.Clear();
                        Thread.Sleep(750);
                    }
                }
                else
                    System.Windows.Forms.MessageBox.Show("Bağlantı Açılamadı !");

                _serial.Close();
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        public void FisSatirGonder(List<HareketSatiri> lines)
        {
            throw new NotImplementedException();
        }
    }

    public class Hugin_425TX : IYazarKasa
    {
        public string PortNo { get; set; }
        SerialPort _serial;
        enum TamamlamaSekli
        {
            Sagdan,
            Soldan
        }

        private string Doldur(string kaynakDeger, int toplamUzunluk, TamamlamaSekli tip, string doldurulacakVeri)
        {
            string sonuc = string.Empty;
            if (kaynakDeger.Length > toplamUzunluk)
                return kaynakDeger.Substring(0, toplamUzunluk);

            if (tip == TamamlamaSekli.Sagdan)
                sonuc = kaynakDeger;

            for (int i = 0; i < toplamUzunluk - kaynakDeger.Length; i++)
            {
                sonuc += doldurulacakVeri;
            }

            if (tip == TamamlamaSekli.Soldan)
                sonuc += kaynakDeger;

            return sonuc;
        }


        public void StokGonder()
        {
            using (SksEntity ent = new SksEntity())
            {
                var result = (from b in ent.Barkodlar
                              join s in ent.Stoklar on b.StokID equals s.ID
                              join v in ent.VergiOranlari on s.VergiID equals v.ID
                              select new { b.Barkodu, s.Adi, s.Fiyat1, v.Sira }).ToList();

                string pluKodu = string.Empty;

                using (StreamWriter sw = new StreamWriter("HuginAlpha.txt", false))
                {
                    foreach (var item in ent.VergiOranlari.ToList())
                    {
                        pluKodu = Doldur("299900" + item.Sira.ToString(), 14, TamamlamaSekli.Sagdan, " ");
                        sw.WriteLine(string.Format("{0},{1},003,016,124,004,000,0             ,{2},{3}", pluKodu, Doldur(item.Aciklama.RemoveTurkis(), 19, TamamlamaSekli.Sagdan, " "), (item.Sira + 1).ToString("00"), (1000m).ToString("0000000000")));
                    }

                    foreach (var item in result)
                    {
                        pluKodu = Doldur(item.Barkodu, 14, TamamlamaSekli.Sagdan, " ");
                        sw.WriteLine(string.Format("{0},{1},003,016,124,004,000,0             ,{2},{3}", pluKodu, Doldur(item.Adi.RemoveTurkis(), 19, TamamlamaSekli.Sagdan, " "), (item.Sira + 1).ToString("00"), Doldur(item.Fiyat1.ToString("n2").Replace(".", "").Replace(",", ""), 10, TamamlamaSekli.Soldan, "0")));
                    }
                    sw.Close();
                }

                if (File.Exists("hugin.exe") && File.Exists("HuginAlpha.dll"))
                {
                    ProcessStartInfo ps = new ProcessStartInfo("hugin.exe", string.Format("{0} {1} {2}", this.PortNo.Replace("COM", ""), 1, 0));
                    ps.WindowStyle = ProcessWindowStyle.Normal;
                    Process p = Process.Start(ps);
                    p.WaitForExit();
                }
                else
                    System.Windows.Forms.MessageBox.Show("Yazarkasa programı bulunamadı");
            }
        }

        public void DepartmanGonder()
        {
            KdvBilgisi();
            DeparmanBilgisi();
        }

        private string KdvFormat(int kdvOran)
        {
            switch (kdvOran)
            {
                case 0:
                    return "007";
                case 1:
                    return "011";
                case 8:
                    return "019";
                case 18:
                    return "035";
                case 4:
                    return "067";
                case 5:
                    return "131";
                default:
                    return "003";
            }
        }

        private void DeparmanBilgisi()
        {
            using (SksEntity ent = new SksEntity())
            {
                var result = (from v in ent.VergiOranlari where v.Oran < 30 select new { v.Aciklama, v.Sira, v.Oran }).Take(12).ToList();
                using (StreamWriter sw = new StreamWriter("HuginAlpha.txt", false))
                {
                    foreach (var item in result)
                    {
                        sw.WriteLine(string.Format("{0},{3},000,124,004,000,{1},{2}", Doldur(item.Aciklama.RemoveTurkis(), 19, TamamlamaSekli.Sagdan, " "), "00", (10m).ToString("0000000000"), KdvFormat((int)item.Oran)));
                    }
                    sw.Close();
                }

                if (File.Exists("hugin.exe") && File.Exists("HuginAlpha.dll"))
                {
                    ProcessStartInfo ps = new ProcessStartInfo("hugin.exe", string.Format("{0} {1} {2}", this.PortNo.Replace("COM", ""), 1, 2));
                    ps.WindowStyle = ProcessWindowStyle.Normal;
                    Process p = Process.Start(ps);
                    p.WaitForExit();
                }
                else
                    System.Windows.Forms.MessageBox.Show("Yazarkasa programı bulunamadı");
            }
        }
        private void KdvBilgisi()
        {
            using (SksEntity ent = new SksEntity())
            {
                var result = (from v in ent.VergiOranlari where v.Oran < 30 orderby v.Sira group v by v.Oran into g select new { g.Key }).Take(8).ToList();

                using (StreamWriter sw = new StreamWriter("HuginAlpha.txt", false))
                {
                    foreach (var item in result)
                    {
                        sw.WriteLine(string.Format("{0}", item.Key.ToString("00")));
                    }
                    sw.Close();
                }

                if (File.Exists("hugin.exe") && File.Exists("HuginAlpha.dll"))
                {
                    ProcessStartInfo ps = new ProcessStartInfo("hugin.exe", string.Format("{0} {1} {2}", this.PortNo.Replace("COM", ""), 1, 1));
                    ps.WindowStyle = ProcessWindowStyle.Normal;
                    Process p = Process.Start(ps);
                    p.WaitForExit();
                }
                else
                    System.Windows.Forms.MessageBox.Show("Yazarkasa programı bulunamadı");
            }
        }


        public void FisSatirGonder(params string[] lines)
        {
            _serial = new SerialPort(this.PortNo);
            try
            {
                _serial.Open();

                if (_serial.IsOpen)
                {
                    foreach (string item in lines)
                    {
                        _serial.Write(item + "\r");
                        Thread.Sleep(500);
                    }
                }
                else
                    System.Windows.Forms.MessageBox.Show("Bağlantı Açılamadı !");

                _serial.Close();
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
        }

        public void FisSatirGonder(List<HareketSatiri> lines)
        {
            throw new NotImplementedException();
        }
    }
}
